package com.aaa.util;

import com.madgag.gif.fmsware.AnimatedGifEncoder;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.springframework.stereotype.Component;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;


@Slf4j
@Component
public  class ImageGif {

    public static void main(String[] args) throws IOException {
        try {
            fetchFrame("C:\\Users\\82672\\Videos\\Captures\\IMG_18321.MP4", ".jpg", 100);
        } catch (Exception e) {
            buildGif("C:\\Users\\82672\\Videos\\Captures\\IMG_18321.MP4", 10, 10, 3, 50);
            e.printStackTrace();
        }
    }
    /**
     * 截取视频指定帧生成gif
     *
     * @param videofile  视频文件
     * @param startFrame 开始帧
     * @param frameCount 截取帧数
     * @param frameRate  帧频率（默认：3）
     * @param margin     每截取一次跳过多少帧（默认：3）
     * @throws java.io.IOException 截取的长度超过视频长度
     */
    public static String buildGif(String videofile, int startFrame, int frameCount, Integer frameRate, Integer margin) throws IOException {
        BufferedImage bufferedImage = null;
        if (margin == null) {
            margin = 3;
        }
        if (frameRate == null) {
            frameRate = 3;
        }
        String url= videofile.substring(0, videofile.lastIndexOf(".")) + ".gif";
        FileOutputStream targetFile = new FileOutputStream(url);
        //获取视频的帧信息
        FFmpegFrameGrabber ff = new FFmpegFrameGrabber(videofile);
        //开始
        ff.start();
        //获取rotate度
        String rotate = ff.getVideoMetadata("rotate");
//        log.info(rotate);
        try {
            //帧数不够
            if (startFrame > ff.getLengthInFrames() & (startFrame + frameCount) > ff.getLengthInFrames()) {
                throw new RuntimeException("THE VIDEO IS TOO SHORT!");
            }
            if(margin*frameCount+startFrame>ff.getLengthInFrames()){
                frameCount=5;
            }
            ff.setFrameNumber(startFrame);
            AnimatedGifEncoder en = new AnimatedGifEncoder();
            en.setFrameRate(frameRate);
            en.start(targetFile);
            for (int i = 0; i < frameCount; i++) {
                Frame frame = ff.grabImage();
//                Frame f = (Frame) convert;
                if (null != rotate && rotate.length() > 1) {
                    bufferedImage = doExcuteFrame(frame,true);
                } else{
                    bufferedImage = doExcuteFrame(frame,false);
                }
                en.addFrame(bufferedImage);
                ff.setFrameNumber(ff.getFrameNumber() + margin);
            }
            en.finish();
        } finally {
            ff.stop();
            ff.close();
        }
        return url;
    }


    /**
     * 截取视频指定帧保存为指定格式的图片（图片保存在视频同文件夹下）
     *
     * @param videofile  视频地址
     * @param imgSuffix  图片格式
     * @param indexFrame 第几帧（默认：5）
     * @throws Exception
     */
    public static String fetchFrame(String videofile, String imgSuffix, Integer indexFrame) throws Exception {
        BufferedImage targetFilePath = null;
        if (indexFrame == null) {
            indexFrame = 5;
        }
        Integer suffixIndex = videofile.lastIndexOf(".");
        String url= (suffixIndex != -1 ? videofile.substring(0, suffixIndex) : videofile) + imgSuffix;
        File targetFile = new File(url);

        try (FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(videofile);
             OutputStream outputStream = new FileOutputStream(targetFile)) {
            ff.start();
            String rotate = ff.getVideoMetadata("rotate");
            ff.setFrameNumber(indexFrame);
            Frame f = ff.grabImage();
            if (null != rotate && rotate.length() > 1) {
                targetFilePath = doExcuteFrame(f, true);
            } else {
                targetFilePath = doExcuteFrame(f, false);
            }
//            Java2DFrameConverter converter = new Java2DFrameConverter();
//            BufferedImage fecthedImage = converter.getBufferedImage(f);
            ImageIO.write(targetFilePath, "jpg", outputStream);
        }
        return url;
    }


    public static BufferedImage doExcuteFrame(Frame f, boolean bool) throws IOException {
        if(null==f && null==f.image){
            return null;
        }
        Java2DFrameConverter java2DFrameConverter = new Java2DFrameConverter();
        BufferedImage bufferedImage = java2DFrameConverter.getBufferedImage(f);
        if (bool==true){
            Image img= (Image)bufferedImage;
            bufferedImage=rotate(img,90);
        }
//        String whole = secl.whole(LocalTime.now());
//        ImageIO.write(bufferedImage,"png",new File("D:/idea/queick"+"/张三/video/"+whole+"/"+whole+".jpg"));

//        Image im=(Image) bufferedImage;
//        im.
//        String filename = im.getOriginalFilename();
//        if (!filename.equals("")){
//            File file = new File("D:/aaa/" + filename);
//            im.transferTo(file);
//        }
        return bufferedImage;
    }

    /**
     * 将图片旋转指定度
     *
     * @param bufferedimage 图片
     * @param degree        旋转角度
     * @return
     */
    public static BufferedImage rotateImage(BufferedImage bufferedimage, int degree) {
        // 得到图片宽度。
        int w = bufferedimage.getWidth();
        // 得到图片高度。
        int h = bufferedimage.getHeight();
        // 得到图片透明度。
        int type = bufferedimage.getColorModel().getTransparency();
        // 空的图片。
        BufferedImage img;
        // 空的画笔。
        Graphics2D graphics2d;
        (graphics2d = (img = new BufferedImage(w, h, type))
                .createGraphics()).setRenderingHint(
                RenderingHints.KEY_INTERPOLATION,
                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        // 旋转，degree是整型，度数，比如垂直90度。
        graphics2d.rotate(Math.toRadians(degree), w / 2, h / 2);
        // 从bufferedimagecopy图片至img，0,0是img的坐标。
        graphics2d.drawImage(bufferedimage, 0, 0, null);
        graphics2d.dispose();
        // 返回复制好的图片，原图片依然没有变，没有旋转，下次还可以使用。
        return img;
    }

    /**
     * 图片旋转角度
     *
     * @param src   源图片
     * @param angel 角度
     * @return 目标图片
     */
    public static BufferedImage rotate(Image src, int angel) {
        int src_width = src.getWidth(null);
        int src_height = src.getHeight(null);
        // calculate the new image size
        Rectangle rect_des = CalcRotatedSize(new Rectangle(new Dimension(
                src_width, src_height)), angel);

        BufferedImage res = null;
        res = new BufferedImage(rect_des.width, rect_des.height,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = res.createGraphics();
        // transform(这里先平移、再旋转比较方便处理；绘图时会采用这些变化，绘图默认从画布的左上顶点开始绘画，源图片的左上顶点与画布左上顶点对齐，然后开始绘画，修改坐标原点后，绘画对应的画布起始点改变，起到平移的效果；然后旋转图片即可)

        //平移（原理修改坐标系原点，绘图起点变了，起到了平移的效果，如果作用于旋转，则为旋转中心点）
        g2.translate((rect_des.width - src_width) / 2, (rect_des.height - src_height) / 2);


        //旋转（原理transalte(dx,dy)->rotate(radians)->transalte(-dx,-dy);修改坐标系原点后，旋转90度，然后再还原坐标系原点为(0,0),但是整个坐标系已经旋转了相应的度数 ）
        g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2);

//        //先旋转（以目标区域中心点为旋转中心点，源图片左上顶点对准目标区域中心点，然后旋转）
//        g2.translate(rect_des.width/2,rect_des.height/ 2);
//        g2.rotate(Math.toRadians(angel));
//        //再平移（原点恢复到源图的左上顶点处（现在的右上顶点处），否则只能画出1/4）
//        g2.translate(-src_width/2,-src_height/2);


        g2.drawImage(src, null, null);
        return res;
    }

    /**
     * 计算转换后目标矩形的宽高
     *
     * @param src   源矩形
     * @param angel 角度
     * @return 目标矩形
     */
    private static Rectangle CalcRotatedSize(Rectangle src, int angel) {
        double cos = Math.abs(Math.cos(Math.toRadians(angel)));
        double sin = Math.abs(Math.sin(Math.toRadians(angel)));
        int des_width = (int) (src.width * cos) + (int) (src.height * sin);
        int des_height = (int) (src.height * cos) + (int) (src.width * sin);
        return new java.awt.Rectangle(new Dimension(des_width, des_height));
    }

}
